package top.z.work.module.system.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import top.z.work.framework.common.exception.ExceptionUtil;
import top.z.work.framework.common.exception.ServiceException;
import top.z.work.module.system.constant.SystemErrorCode;
import top.z.work.module.system.controller.role.vo.SystemRoleRelateRouteCreateVO;
import top.z.work.module.system.controller.role.vo.SystemRoleRelateRouteVO;
import top.z.work.module.system.controller.role.vo.SystemRoleRelateUserCreateVO;
import top.z.work.module.system.convert.SystemRoleConvert;
import top.z.work.module.system.entity.*;
import top.z.work.module.system.entity.table.SystemUserRoleTableDef;
import top.z.work.module.system.entity.table.SystemUserTableDef;
import top.z.work.module.system.mapper.SystemRoleMapper;
import top.z.work.module.system.mapper.SystemRoleRouteMapper;
import top.z.work.module.system.mapper.SystemRouteMapper;
import top.z.work.module.system.mapper.SystemUserRoleMapper;
import top.z.work.module.system.service.SystemRoleService;

import java.util.List;
import java.util.Objects;

/**
 * 系统角色ServiceImpl
 *
 * @author zaoangod
 * @since 2024-03-22
 */
@Slf4j
@Service
public class SystemRoleServiceImpl extends ServiceImpl<SystemRoleMapper, SystemRole> implements SystemRoleService {

    @Resource
    SystemRouteMapper     systemRouteMapper;
    @Resource
    SystemUserRoleMapper  systemUserRoleMapper;
    @Resource
    SystemRoleRouteMapper systemRoleRouteMapper;

    /**
     * 移除角色
     *
     * @param identity 角色ID
     */
    @Override
    public void removeRole(Long identity) {
        if (identity == null || identity == 0) {
            throw new ServiceException(SystemErrorCode.ROLE_ID_NOT_EMPTY);
        }
        // 判断角色是否被分配给用户
        var userQuery     = QueryChain.of(SystemUserRole.class).eq(SystemUserRole::getRoleId, identity);
        var userRoleCount = systemUserRoleMapper.selectCountByQuery(userQuery);
        if (userRoleCount != 0) {
            throw new ServiceException(SystemErrorCode.ROLE_ASSIGN_TO_USER);
        }

        // 删除角色关联路由
        var routeQuery = QueryChain.of(SystemRoleRoute.class).eq(SystemRoleRoute::getRoleId, identity);
        systemRoleRouteMapper.deleteByQuery(routeQuery);

        // 删除角色
        this.removeById(identity);
    }

    /**
     * 修改角色
     *
     * @param parameter 角色ID
     */
    @Override
    public SystemRole modifyRole(SystemRole parameter) {
        // 检测name
        var nameQuery = QueryChain.of(SystemRole.class).eq(SystemRole::getName, parameter.getName());
        if (parameter.getIdentity() != null) {
            nameQuery.ne(SystemRole::getIdentity, parameter.getIdentity());
        }
        if (this.exists(nameQuery)) {
            throw ExceptionUtil.exception(SystemErrorCode.ROLE_NAME_DUPLICATE, parameter.getName());
        }

        // 检测code
        var codeQuery = QueryChain.of(SystemRole.class).eq(SystemRole::getCode, parameter.getCode());
        if (parameter.getIdentity() != null) {
            codeQuery.ne(SystemRole::getIdentity, parameter.getIdentity());
        }
        if (this.exists(codeQuery)) {
            throw ExceptionUtil.exception(SystemErrorCode.ROLE_CODE_DUPLICATE, parameter.getCode());
        }

        this.saveOrUpdate(parameter);
        return parameter;
    }

    /**
     * 获取角色关联的菜单
     *
     * @param identity 角色ID
     * @return 菜单列表
     */
    @Override
    public List<SystemRoleRelateRouteVO> getRoleRelateRoute(Long identity) {
        if (identity == null || identity == 0) {
            throw new ServiceException(SystemErrorCode.ROLE_ID_NOT_EMPTY);
        }
        // 路由列表
        List<SystemRoute> routeList = systemRouteMapper.selectAll();
        // 角色路由关联列表
        QueryChain<SystemRoleRoute> query         = QueryChain.of(SystemRoleRoute.class).eq(SystemRoleRoute::getRoleId, identity);
        List<SystemRoleRoute>       roleRouteList = systemRoleRouteMapper.selectListByQuery(query);

        // 组装数据
        return routeList.stream()
                .map(SystemRoleConvert.INSTANCE::convert)
                .peek(roleRelateRoute -> {
                    for (SystemRoleRoute roleRoute : roleRouteList) {
                        if (roleRelateRoute.getIdentity().equals(roleRoute.getRouteId())) {
                            roleRelateRoute.setRoleRouteId(roleRoute.getRoleRouteId());
                        }
                    }
                })
                .toList();
    }

    /**
     * 添加角色关联的菜单
     *
     * @param parameter 参数
     */
    @Override
    public void addRoleRelateRoute(SystemRoleRelateRouteCreateVO parameter) {
        if (parameter.getRoleId() == null) {
            throw new ServiceException(SystemErrorCode.ROLE_ID_NOT_EMPTY);
        }
        if (parameter.getRouteId() == null || parameter.getRouteId().isEmpty()) {
            throw new ServiceException(SystemErrorCode.ROLE_RELATE_ROUTE_ID_NOT_EMPTY);
        }
        QueryChain<SystemRoleRoute> query = QueryChain.of(SystemRoleRoute.class).eq(SystemRoleRoute::getRoleId, parameter.getRoleId());
        systemRoleRouteMapper.deleteByQuery(query);

        List<SystemRoleRoute> list = parameter.getRouteId().stream()
                .filter(Objects::nonNull)
                .map(routeId -> new SystemRoleRoute().setRoleId(parameter.getRoleId()).setRouteId(routeId))
                .toList();
        systemRoleRouteMapper.insertBatch(list);
    }

    /**
     * 获取角色关联的用户
     *
     * @param identity 角色ID
     * @param page     页码
     * @param size     页大小
     * @return 菜单列表
     */
    @Override
    public Page<SystemUser> getRoleRelateUser(Long identity, Integer page, Integer size) {
        if (identity == null) {
            throw new ServiceException(SystemErrorCode.ROLE_ID_NOT_EMPTY);
        }
        Page<SystemUser> pageInfo = Page.of(page, size);

        QueryWrapper query = QueryChain.create()
                .select(SystemUserTableDef.SYSTEM_USER.ALL_COLUMNS)
                .from(SystemUserRoleTableDef.SYSTEM_USER_ROLE)
                .leftJoin(SystemUserTableDef.SYSTEM_USER).on(SystemUserRoleTableDef.SYSTEM_USER_ROLE.USER_ID.eq(SystemUserTableDef.SYSTEM_USER.IDENTITY))
                .where(SystemUserRoleTableDef.SYSTEM_USER_ROLE.ROLE_ID.eq(identity));

        return systemRoleRouteMapper.paginateAs(pageInfo, query, SystemUser.class);
    }

    /**
     * 添加角色到用户
     *
     * @param parameter 参数
     */
    @Override
    public void addRoleRelateUser(SystemRoleRelateUserCreateVO parameter) {
        if (parameter.getRoleId() == null) {
            throw new ServiceException(SystemErrorCode.ROLE_ID_NOT_EMPTY);
        }
        if (parameter.getUserId() == null || parameter.getUserId().isEmpty()) {
            throw new ServiceException(SystemErrorCode.ROLE_RELATE_USER_ID_NOT_EMPTY);
        }

        parameter.getUserId().forEach(userId -> {
            QueryWrapper query = QueryChain.create()
                    .where(SystemUserRoleTableDef.SYSTEM_USER_ROLE.ROLE_ID.eq(parameter.getRoleId()))
                    .and(SystemUserRoleTableDef.SYSTEM_USER_ROLE.USER_ID.eq(userId));
            systemUserRoleMapper.deleteByQuery(query);
        });
        systemUserRoleMapper.insertBatch(
                parameter.getUserId()
                        .stream()
                        .map(userId -> new SystemUserRole().setRoleId(parameter.getRoleId()).setUserId(userId))
                        .toList()
        );
    }

    /**
     * 删除角色关联的用户
     *
     * @param parameter 参数
     */
    @Override
    public void removeRoleRelateUser(SystemRoleRelateUserCreateVO parameter) {
        if (parameter.getRoleId() == null) {
            throw new ServiceException(SystemErrorCode.ROLE_ID_NOT_EMPTY);
        }
        if (parameter.getUserId() == null || parameter.getUserId().isEmpty()) {
            throw new ServiceException(SystemErrorCode.ROLE_RELATE_USER_ID_NOT_EMPTY);
        }

        parameter.getUserId().forEach(userId -> {
            QueryWrapper query = QueryChain.create()
                    .where(SystemUserRoleTableDef.SYSTEM_USER_ROLE.ROLE_ID.eq(parameter.getRoleId()))
                    .and(SystemUserRoleTableDef.SYSTEM_USER_ROLE.USER_ID.eq(userId));
            systemUserRoleMapper.deleteByQuery(query);
        });
    }

}
